#ifndef __BLOCK_VECTOR_IMPL_H__
#define __BLOCK_VECTOR_IMPL_H__

/**
 * COPYRIGHT NOTICE
 * Copyright (C) SHFL Entertainment
 * All rights reserved
 * 
 * @file block_vector_impl.h
 * @brief use the c++ MPL to reduce the loop calculation
 * if you want to improve the vector performace more, please
 * use SIMD to do the optimization
 * 
 * 
 * @version 1.0.0
 * @date 2014-02-26
 * @author zhen zhang zhezhang@shfl.com
 */
#include "block_types.h"

template<typename T, int N>
struct vector_impl
{
    template<typename U>
    static void DoCopy(T out[N], U const rhs[N])
    {
        out[0] = static_cast<T>(rhs[0]);
        vector_impl<T, N - 1>::DoCopy(out + 1, rhs + 1);
    }

    static void DoAssign(T out[N], T const & rhs)
    {
        out[0] = rhs;
        vector_impl<T, N - 1>::DoAssign(out + 1, rhs);
    }

    static void DoAdd(T out[N], T const lhs[N], T const rhs[N])
    {
        out[0] = lhs[0] + rhs[0];
        vector_impl<T, N - 1>::DoAdd(out + 1, lhs + 1, rhs + 1);
    }

    static void DoAdd(T out[N], T const lhs[N], T const & rhs)
    {
        out[0] = lhs[0] + rhs;
        vector_impl<T, N - 1>::DoAdd(out + 1, lhs + 1, rhs);
    }

    static void DoSub(T out[N], T const lhs[N], T const rhs[N])
    {
        out[0] = lhs[0] - rhs[0];
        vector_impl<T, N - 1>::DoSub(out + 1, lhs + 1, rhs + 1);
    }

    static void DoSub(T out[N], T const lhs[N], T const & rhs)
    {
        out[0] = lhs[0] - rhs;
        vector_impl<T, N - 1>::DoSub(out + 1, lhs + 1, rhs);
    }

    static void DoMul(T out[N], T const lhs[N], T const rhs[N])
    {
        out[0] = lhs[0] * rhs[0];
        vector_impl<T, N - 1>::DoMul(out + 1, lhs + 1, rhs + 1);
    }

    static void DoScale(T out[N], T const lhs[N], T const & rhs)
    {
        out[0] = lhs[0] * rhs;
        vector_impl<T, N - 1>::DoScale(out + 1, lhs + 1, rhs);
    }

    static void DoDiv(T out[N], T const lhs[N], T const rhs[N])
    {
        out[0] = lhs[0] / rhs[0];
        vector_impl<T, N - 1>::DoDiv(out + 1, lhs + 1, rhs + 1);
    }

    static void DoNegate(T out[N], T const rhs[N])
    {
        out[0] = -rhs[0];
        vector_impl<T, N - 1>::DoNegate(out + 1, rhs + 1);
    }

    static bool DoEqual(T const lhs[N], T const rhs[N])
    {
        return (lhs[0] == rhs[0]) && vector_impl<T, N - 1>::DoEqual(lhs + 1, rhs + 1);
    }

    static void DoSwap(T lhs[N], T rhs[N])
    {
        std::swap(lhs[0], rhs[0]);
        vector_impl<T, N - 1>::DoSwap(lhs + 1, rhs + 1);
    }
};



template<typename T>
struct vector_impl<T, 1> // The recursion level should not larger than 17 recommended by standard. Typecial use for vector will no larger than 4
{
    template<typename U>
    static void DoCopy(T out[1], U const rhs[1])
    {
        out[0] = static_cast<T>(rhs[0]);
    }

    static void DoAssign(T out[1], T const & rhs)
    {
        out[0] = rhs;
    }

    static void DoAdd(T out[1], T const lhs[1], T const rhs[1])
    {
        out[0] = lhs[0] + rhs[0];
    }

    static void DoAdd(T out[1], T const lhs[1], T const & rhs)
    {
        out[0] = lhs[0] + rhs;
    }

    static void DoSub(T out[1], T const lhs[1], T const rhs[1])
    {
        out[0] = lhs[0] - rhs[0];
    }

    static void DoSub(T out[1], T const lhs[1], T const & rhs)
    {
        out[0] = lhs[0] - rhs;
    }

    static void DoMul(T out[1], T const lhs[1], T const rhs[1])
    {
        out[0] = lhs[0] * rhs[0];
    }

    static void DoScale(T out[1], T const lhs[1], T const & rhs)
    {
        out[0] = lhs[0] * rhs;
    }

    static void DoDiv(T out[1], T const lhs[1], T const rhs[1])
    {
        out[0] = lhs[0] / rhs[0];
    }

    static void DoNegate(T out[1], T const rhs[1])
    {
        out[0] = -rhs[0];
    }

    static bool DoEqual(T const lhs[1], T const rhs[1])
    {
        return lhs[0] == rhs[0];
    }

    static void DoSwap(T lhs[1], T rhs[1])
    {
        std::swap(lhs[0], rhs[0]);
    }

};




#endif
